package com.egg.auth.controller.web;

import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.temp.SaTempUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.egg.auth.entity.user.User;
import com.egg.auth.entity.user.UserAccount;
import com.egg.auth.enums.account.AccountTypeEnum;
import com.egg.auth.model.request.Login;
import com.egg.auth.model.request.web.AccountOnPasswordPost;
import com.egg.auth.model.request.web.PasswordPatch;
import com.egg.auth.model.request.web.ResetPasswordPatch;
import com.egg.auth.model.response.web.LoginCaptcha;
import com.egg.auth.service.login.ILoginFactory;
import com.egg.auth.service.user.IUserAccountService;
import com.egg.auth.service.user.IUserService;
import com.egg.auth.utils.PasswordUtil;
import com.egg.basic.fegin.BasicCaptchaFeignClient;
import com.egg.basic.model.response.CaptchaInfo;
import com.egg.common.context.util.LocalThreadContextUtils;
import com.egg.common.core.enums.ResponseCode;
import com.egg.common.core.exception.CustomException;
import com.egg.common.core.model.controller.WebController;
import com.egg.common.core.model.response.ResponseData;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * @author east
 */
@Slf4j
@Api(tags = WebController.API_PREFIX + "账号中心")
@RestController
@RequestMapping("/account")
public class WebAccountController extends WebController {


    @Autowired
    private IUserAccountService userAccountService;
    @Autowired
    private BasicCaptchaFeignClient basicCaptchaFeignClient;
    @Autowired
    private IUserService userService;


    @ApiOperation(value = "账号注册-账号密码")
    @PostMapping("/registered/password/let")
    public ResponseData<String> userRegisteredPost(@RequestBody AccountOnPasswordPost param) {
        Long userId = userAccountService.addOnPassword(param);
        return ResponseData.success(userId.toString());
    }

    @ApiOperation(value = "获取登录验证码")
    @GetMapping("/login/captcha/let")
    public ResponseData<LoginCaptcha> createLoginCaptchaGet() {
        // 可以根据业务需求, 业务服务单独配置验证码开关,
        // 1. 基础服务处理开启状态, 业务服务可单独关闭,
        // 2. 基础服务出现异常, 也可关闭业务验证, 保证服务可用
        CaptchaInfo captchaInfo;
        if (null == basicCaptchaFeignClient) {
            // 当基础服务feign未被扫描到, 则不开启验证码
            captchaInfo = new CaptchaInfo();
            captchaInfo.setEnabled(false);
        } else {
            ResponseData<CaptchaInfo> rd = basicCaptchaFeignClient.captchaImageCreateGet();
            if (rd.isError()) {
                return ResponseData.error(rd.getMsg());
            }
            captchaInfo = rd.getData();
        }
        LoginCaptcha loginCaptcha = new LoginCaptcha();
        loginCaptcha.setEnabled(captchaInfo.getEnabled());
        loginCaptcha.setId(captchaInfo.getId());
        loginCaptcha.setBase64(captchaInfo.getBase64());
        return ResponseData.success(loginCaptcha);
    }

    @ApiOperation(value = "登录")
    @PostMapping("/login/let")
    public ResponseData<String> login(@RequestBody Login login) {
        Optional<ILoginFactory> proc = ILoginFactory.findFactory(login.getAccountType());
        if (!proc.isPresent()) {
            throw new CustomException("accountType :" + login.getAccountType());
        }
        return proc.get().login(login);
    }

    @ApiOperation(value = "退出登录")
    @DeleteMapping("/logout/let")
    public ResponseData<String> logout() {
        if (StpUtil.isLogin()) {
            StpUtil.logout();
        }
        return ResponseData.success();
    }

    @ApiOperation(value = "强制退出指定用户")
    @DeleteMapping("/kickout")
    public ResponseData<String> kickout(
            @ApiParam(value = "ID集合", required = true) @RequestParam(value = "ids") Collection<String> ids
    ) {
        List<User> userList = userService.baseFindById(ids);
        if (ObjectUtil.isEmpty(userList)) {
            return ResponseData.success();
        }
        Long userId = LocalThreadContextUtils.getUserId();
        for (User user : userList) {
            if (Objects.equals(userId, user.getId())) {
                throw new CustomException("不允许下线自己");
            }
            StpUtil.kickout(user.getId());
        }
        return ResponseData.success();
    }

    @ApiOperation(value = "修改密码")
    @PatchMapping("/password")
    public ResponseData<String> accountPasswordPut(@RequestBody PasswordPatch param) {
        Optional<UserAccount> userAccountOpt = userAccountService.findByUserId(LocalThreadContextUtils.getUserId(), AccountTypeEnum.PASSWORD);
        if (!userAccountOpt.isPresent()) {
            return ResponseData.error("没有初始化密码账号");
        }
        UserAccount userAccount = new UserAccount();
        if (!PasswordUtil.equalsPassword(param.getOldPassword(), userAccountOpt.get().getPassword())) {
            return ResponseData.error(ResponseCode.CUSTOM_ERROR.getCode(), "旧密码错误");
        }
        userAccount.setId(userAccountOpt.get().getId());
        userAccount.setPassword(PasswordUtil.encryptionPassword(param.getNewPassword()));
        userAccountService.baseEdit(userAccount);
        return ResponseData.success(userAccount.getId().toString());
    }

    @ApiOperation(value = "重置密码")
    @PatchMapping("/reset/password")
    public ResponseData<String> accountResetPasswordPut(@RequestBody ResetPasswordPatch param) {
        if (ObjectUtil.isEmpty(param.getPassword())) {
            return ResponseData.error(ResponseCode.PARAM_INVALID);
        }
        Optional<UserAccount> userAccountOpt = userAccountService.findByUserId(param.getUserId(), AccountTypeEnum.PASSWORD);
        if (!userAccountOpt.isPresent()) {
            return ResponseData.error("没有初始化密码账号");
        }
        UserAccount userAccount = new UserAccount();
        userAccount.setId(userAccountOpt.get().getId());
        userAccount.setPassword(PasswordUtil.encryptionPassword(param.getPassword()));
        userAccountService.baseEdit(userAccount);
        return ResponseData.success(userAccount.getId().toString());
    }

    @ApiOperation(value = "查看token")
    @GetMapping("/clearly/token")
    public ResponseData<SaTokenInfo> clearly() {
        return ResponseData.success(StpUtil.getTokenInfo());
    }

    @ApiOperation(value = "颁发邀请码")
    @PostMapping("/invited/code")
    public ResponseData<String> createTempCodePost(@RequestBody JSONObject param) {
        // 根据 value 创建一个 邀请码
        return ResponseData.success(SaTempUtil.createToken(param, 300));
    }

    @ApiOperation(value = "邀请码换取值")
    @GetMapping("/invited/{code}/to/value/let")
    public ResponseData<JSONObject> tempCodeValueGet(@PathVariable String code) {
        // 解析 code 获取 value，并转换为指定类型
        long time = SaTempUtil.getTimeout(code);
        if (time <= SaTokenDao.NOT_VALUE_EXPIRE) {
            return ResponseData.error(ResponseCode.PARAM_INVALID);
        }
        JSONObject value = SaTempUtil.parseToken(code, JSONObject.class);
        return ResponseData.success(value);
    }


}
